package com.byl.common.modules.service.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.byl.common.modules.service.TokenService;
import com.byl.common.utils.PemUtils;
import com.byl.sdk.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.*;

/**
 * Created by Administrator on 2019/12/5.
 */
@Service
public class TokenServiceImpl implements TokenService {
    private final Logger logger=LoggerFactory.getLogger(TokenServiceImpl.class);
    final String EXPIRE_MSG="The Token has expired on";
    @Value("${token.rsa_public_pem}")
    String rsa_public_pem;
    @Value("${token.rsa_private_pem}")
    String rsa_private_pem;
    @Value("${token.token_life_cicle}")
    long token_life_cicle;
    @Value("${token.issuer}")
    String issuer;
    @Value("${token.token_algorithm}")
    String token_algorithm;

    RSAPublicKey publicKey = null;
    RSAPrivateKey privateKey = null;
    Algorithm algorithm=null;



    @Override
    public String getToken(Map<String,Object> map) {
        try {
            JWTCreator.Builder builder=JWT.create()
                    .withIssuer(issuer)
                    .withExpiresAt(getLifeTime());
            //遍歷參數
            if (null != map) {
                Iterator<Map.Entry<String,Object>> it=map.entrySet().iterator();
                while(it.hasNext()){
                    Map.Entry<String,Object> entry=it.next();
                    builder.withClaim(entry.getKey(),entry.getValue().toString());
                }
            }
            return builder.sign(getAlgorithm());
        } catch (JWTCreationException exception){
              logger.error("###获取token异常:"+exception.getMessage());
        }
        return null;
    }

    @Override
    public int verifyToken(String token) {
        try {
            JWTVerifier verifier = JWT.require(getAlgorithm())
                    .withIssuer(issuer)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return 1;
        } catch (JWTVerificationException exception){
            String msg=exception.getMessage();
            logger.error("###token验证结果:"+msg);
            if(msg.startsWith(EXPIRE_MSG)){
                return 2;
            }
            return 3;
        }
    }

    @Override
    public String decodeToken(String token) {
        DecodedJWT jwt = JWT.decode(token);
        Map<String,Claim> map= jwt.getClaims();
        Iterator<Map.Entry<String,Claim>> it= map.entrySet().iterator();
        while (it.hasNext()){
            Map.Entry<String,Claim> entry=it.next();
           logger.info(entry.getKey()+"===="+entry.getValue().asString());
        }
       logger.info("#####"+jwt.getIssuer());
        return null;
    }

    @Override
    public String refreshToken(String token) {
        if(StringUtil.isBlank(token))
            return null;
        DecodedJWT jwt=null;
        try {
            JWTVerifier verifier = JWT.require(getAlgorithm())
                    .withIssuer(issuer)
                    .build();
             jwt = verifier.verify(token);
        } catch (JWTVerificationException exception){
            String msg=exception.getMessage();
            if(msg.startsWith(EXPIRE_MSG)){
                jwt=JWT.decode(token);
               return  JWT.create()
                        .withIssuer(issuer)
                        .withExpiresAt(getLifeTime())
                        .withClaim("id",jwt.getClaim("id").asString())
                        .withClaim("username",jwt.getClaim("username").asString())
                        .sign(getAlgorithm());

            }else{
                logger.error("###刷新token异常:"+msg);
                return null;
            }
        }
        return token;
    }

    public RSAPublicKey getPublicKey() {
        if(null==publicKey){
            try {
                publicKey= (RSAPublicKey) PemUtils.readPublicKeyFromFile(rsa_public_pem,token_algorithm);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return publicKey;
    }

    public RSAPrivateKey getPrivateKey() {
        if(null==privateKey){
            try {
                privateKey= (RSAPrivateKey) PemUtils.readPrivateKeyFromFile(rsa_private_pem,token_algorithm);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return privateKey;
    }

    public long getToken_life_cicle() {
        if(this.token_life_cicle==0){
            this.token_life_cicle=1000*60*60; //如果没有 设置默认一小时
        }
        return token_life_cicle;
    }

    public Algorithm getAlgorithm() {
        if(null==this.algorithm){
            this.algorithm=Algorithm.RSA256(getPublicKey(), getPrivateKey());
        }
        return this.algorithm;
    }

    private Date getLifeTime(){
        Calendar calendar=Calendar.getInstance();
        Date now=calendar.getTime();
        now.setTime(System.currentTimeMillis()+getToken_life_cicle());
        return now;
    }
}
